/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package transferencia;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * Esta classe orefece operações para a criação e manuzeio da árvore
 * @author lljotall
 * @param <T> Type of node's information.
 */
public class TreeTO<T> {
    protected int height;
    protected T root;
    protected HashMap<T, List<T>> data;
 /**
     * Cria uma árcore a partir do nó raiz.
     * @param root Conteúdo do nó raiz.
     */
    TreeTO(T root){
        data = new HashMap<T, List<T>>();
        data.put(root, null);
        
        this.root = root;
        
        height = 1;
    }

    /**
     * Adiciona um nó na árvore. 
     * Se o nó não existe na árvore, ele será adicionado.     
     * @param from Conteúdo do nó pai
     * @param to Conteúdo do nó filho
     */
    public void add(T from, T to){
        if(data.get(from) == null){
            data.put(from, new ArrayList(Arrays.asList(to)));
            height = recalculateHeight(root);
        }
        else{
            List<T> neighbors = data.get(from);
            if(!neighbors.contains(to)){
                data.get(from).add(to);
            }
            data.put(to, null);
        }
    }
    
    /**
     * Retorna todos os nós da árvore
     * @return Um conjunto da classe Set com todos os nós inseridos na árvore
     */
    public Set<T> getNodes(){
        return data.keySet();
    }
    
    /**
     * Retorna todos os nós vizinhos do parâmetro.
     * @param node Nó de onde o usuário deseja obter os vizinhos.
     * @return Uma lista que contém todos os vizinhos do nó desejado.
     */
    public List<T> getNeighbors(T node){
        return data.get(node);
    }
    
    /**
     * Returns altura da árvore.
     * @return altura da árvore.
     */
    public int getHeight() {
        return height;
    }

    /**
     * Returna a raiz da árvore
     * @return raiz da árvore.
     */
    public T getRoot() {
        return root;
    }

    /**
     * Retorna um HashMap contendo toda a informação da árvre.
     * @return um HashMap que contém todos os nós como chaves de todos os fizinhos como dados correspondentes a cada um desses nós. 
     */
    public HashMap<T, List<T>> getData() {
        return data;
    }
    
    private int recalculateHeight(T node){
        int maxHeight = 0;
        
        
        if(this.getNeighbors(node) == null)
            return 1;
        else
            for(T neighbor: this.getNeighbors(node)){
                int thisHeight = recalculateHeight(neighbor);
                if(thisHeight > maxHeight)
                    maxHeight = thisHeight;
            }
        
        return maxHeight+1;
    }
}
